﻿using System.ComponentModel;
using System.Threading;

namespace sinetd
{
    /// <summary>
    /// Simple management state of server.
    /// </summary>
    public abstract class ServerController
    {
        /// <summary>
        /// Background worker to run operations asynchronously.
        /// </summary>
        private BackgroundWorker bw;
        /// <summary>
        /// For controlled stop.
        /// </summary>
        private ManualResetEvent mre;

        /// <summary>
        /// Initializes a new instance of sinetd.ServerControler class.
        /// </summary>
        public ServerController()
        {
            bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);

            mre = new ManualResetEvent(false);
        }

        /// <summary>
        /// Gets a value indicating whether the sinetd.ServerController is running and asynchronous operation.
        /// </summary>
        public bool IsRunning { get { return bw.IsBusy; } }

        /// <summary>
        /// Delay in milliseconds between calls of sinetd.ServerControloer.Run.
        /// </summary>
        public int Delay = 100;

        /// <summary>
        /// Starts server in separate thread.
        /// </summary>
        /// <returns>Returns false if server already running, otherwise returns true.</returns>
        public bool Start()
        {
            if (!bw.IsBusy)
            {
                bw.RunWorkerAsync();
                return true;
            }
            return false;
        }

        /// <summary>
        /// Stops server. Blocks until call of method End will be completed.
        /// </summary>
        /// <returns>Returns false if server already in stop state, otherwise returns true after completed stop thread with successful.</returns>
        public bool Stop()
        {
            if (bw.IsBusy)
            {
                mre.Reset();
                bw.CancelAsync();
                mre.WaitOne();
                return true;
            }
            return false;
        }

        /// <summary>
        /// The scheme of server thread.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            Begin();

            while (!bw.CancellationPending)
            {
                Run();
                Thread.Sleep(Delay);
            }

            End();

            mre.Set();
        }

        /// <summary>
        /// Occurs on the begin of running server.
        /// </summary>
        protected abstract void Begin();

        /// <summary>
        /// Occurs many times while server is running, one per Delay in milliseconds.
        /// </summary>
        protected abstract void Run();

        /// <summary>
        /// Occurs on the end of running server.
        /// </summary>
        protected abstract void End();
    }
}
